
/**
 * @file menuEXE.c
 * @author Sevenfite(sevenfite@163.com)
 * @brief 菜单中的执行函数
 * @version 0.1
 * @date 2023-11-12
 * @note 在这里放菜单中要执行的函数
 * @warning 请不要在这里做卡死处理，否则会导致其他地方的轮询失效，这里的函数都是会被轮询的，所以局部变量有很多是静态的
 * @copyright Copyright (c) 2023
 *
 */

#include "menuEXE.h"

#include "ABS_key.h"
#include "BuildTime.h"
#include "C_code_Log.h"
#include "control.h"
#include "display.h"
#include "main.h"
#include "motor.h"
#include "string.h"
#include "tim.h"

/// @brief 显示速度和距离
/// @param key_Num
/// @return
My_StatusTypeDef displaySpeed(int key_Num) {
  int32_t distance = gl_motor.encoderDistance;
  displayStr("LFSpeed:", Display_firstCol, Display_firstRow, RED);
  displayNum(gl_motor.encoderLeftFront, Display_firstCol + 10 * 8,
             Display_firstRow);
  displayStr("LBSpeed:", Display_firstCol, Display_secondRow, RED);
  displayNum(gl_motor.encoderLeftBack, Display_firstCol + 10 * 8,
             Display_secondRow);
  displayStr("RFSpeed:", Display_firstCol, Display_thirdRow, RED);
  displayNum(gl_motor.encoderRightFront, Display_firstCol + 10 * 8,
             Display_thirdRow);
  displayStr("RBSpeed:", Display_firstCol, Display_fourthRow, RED);
  displayNum(gl_motor.encoderRightBack, Display_firstCol + 10 * 8,
             Display_fourthRow);

  // displayStr("dis:", Display_firstCol, Display_fifthRow, RED);
  // displayNum(distance, Display_firstCol + 10 * 8, Display_fifthRow);
  if (key_Num == Key_ESC) {
    return MY_OK;
  }
  return MY_BUSY;
}

/// @brief 测试编码器和PWM
/// @param key_Num
/// @return
My_StatusTypeDef testEncodingAndPWM(int key_Num) {
  static int flag = 0;
  if (flag == 0) {
    flag = 1;
    motorRunModeChange(MOTOR_MODE_SPEED);
  }
  displayStr("LFencoder:", Display_firstCol, Display_firstRow, RED);
  displayNum(gl_motor.encoderLeftFront, Display_firstCol + 8 * 10,
             Display_firstRow);
  displayStr("PWM_ch3:", Display_firstCol, Display_secondRow, RED);
  displayNum(__HAL_TIM_GET_COMPARE(&LEFT_TIM_HANDLE, TIM_CHANNEL_3),
             Display_firstCol + 8 * 10, Display_secondRow);
  displayStr("PWM_ch4:", Display_firstCol, Display_thirdRow, RED);
  displayNum(__HAL_TIM_GET_COMPARE(&LEFT_TIM_HANDLE, TIM_CHANNEL_4),
             Display_firstCol + 8 * 10, Display_thirdRow);
  if (key_Num == Key_ESC) {
    flag = 0;  // 退出时，把标志位改成0
    // MotorPIDAdjustObserver.update = NULL;  //
    // 退出时，把观察者的update函数改成空
    motorRunModeChange(MOTOR_MODE_Direct);  // 退出时，把电机模式改成直接模式
    return MY_READY;
  } else if (key_Num == Key_OK) {
    resetMotorSpeedValue_runTime(0, 0);
    return MY_STANDBY;
  } else if (key_Num == Key_Down) {
    resetMotorSpeedValue_runTime(gl_motor.leftSpeed - 50, gl_motor.rightSpeed);
  } else if (key_Num == Key_UP) {
    resetMotorSpeedValue_runTime(gl_motor.leftSpeed + 50, gl_motor.rightSpeed);
  }

  return MY_BUSY;
}

/// @brief 直接输出PWM
/// @param key_Num
/// @return
My_StatusTypeDef PWMTest(int key_Num) {
  displayStr("encoder:", Display_firstCol, Display_firstRow, RED);
  displayNum(gl_motor.encoderLeftFront, Display_firstCol + 8 * 10,
             Display_firstRow);
  displayNum(__HAL_TIM_GET_COMPARE(&LEFT_TIM_HANDLE, TIM_CHANNEL_3),
             Display_firstCol, Display_secondRow);
  displayNum(__HAL_TIM_GET_COMPARE(&LEFT_TIM_HANDLE, TIM_CHANNEL_4),
             Display_firstCol, Display_thirdRow);
  static int speed_PWM = 0;
  if (key_Num == Key_ESC) {
    speed_PWM = 0;
    return MY_READY;
  } else if (key_Num == Key_OK) {
    return MY_STANDBY;
  } else if (key_Num == Key_Down) {
    speed_PWM -= 50;
    speedAdjustment(speed_PWM, 0);
  } else if (key_Num == Key_UP) {
    speed_PWM += 50;
    speedAdjustment(speed_PWM, 0);
  }

  return MY_BUSY;
}

/// @brief 显示编译时间
/// @param key_Num
/// @return
My_StatusTypeDef buildTime(int key_Num) {
  displayStr(getBuildTime(), Display_firstCol, Display_firstRow, RED);
  displayStr(getBuildDate(), Display_firstCol, Display_secondRow, RED);
  if (key_Num == Key_ESC) {
    return MY_OK;
  }
  return MY_BUSY;
}

/// @brief 进行1号路线的测试
/// @param key_Num
/// @return
My_StatusTypeDef gameDebug(int key_Num) {
  displayStr("gameDebug", Display_firstCol, Display_firstRow, RED);
  if (key_Num == Key_ESC) {
    return MY_OK;
  }
  static uint8_t runTime = 0;
  if (runTime == 0) {
    runTime = 1;
    controlCenterInit(&gl_controlCenter, mapInfo, runMethodTable[0]);
  }
  if (gl_controlCenter.update == MY_READY) {
    LOG("INFO", "路段完成");
    controlCenterUpdate(&gl_controlCenter, mapInfo);
  } else if (gl_controlCenter.update == MY_EXIT) {
    LOG("INFO", "路线完成");
    runTime = 2;
    return MY_OK;
  } else if (gl_controlCenter.update == MY_Running) {
  }
  if (getGlobalTime() % 10 == 0) {
    findLine_Task(&gl_controlCenter);
    speedUpHandle_Task(&gl_controlCenter);
    roadBlocksHandle_Task(&gl_controlCenter);
    speedUpHandle_Task(&gl_controlCenter);
    seekNodeHandle_Task(&gl_controlCenter);
    carParkHandle_Task(&gl_controlCenter);
    rotateHandle_Task(&gl_controlCenter);
  }
  return MY_BUSY;
}

/// @brief 显示数组,无符号8位整型（外部不调用）
/// @param row 显示的y值
/// @param array 8位无符号整型数组
/// @param length 显示的长度
static void show_U8Array(int row, const uint8_t *array, int length) {
  uint8_t colNum_max = Display_lastCol / (3 * 6);  // 一行最多显示的数字个数
  // 遍历数组
  for (int i = 0; i < length; i++) {
    // 计算当前行和列
    int currentRow = row + i / colNum_max * Display_spaced;
    int currentCol = (i % colNum_max) * (3 * 8);

    // 在指定的行和列显示数字
    displayNum_len(array[i], currentCol, currentRow, 3);
  }
}

/// @brief 路段调试函数
/// @param key_Num 
/// @return 
/// @note 重点程序，核心
/// @note 选择路线，选择调试点的个数，选择调试点，进行调试
My_StatusTypeDef Fun_debug(int key_Num) {
  static uint8_t flag =
      0;  // 0:选择路线，1:选择调试点的个数，2:选择调试点（摇号）3:进行调试
  static int8_t tableIndex = 0;       // 选择的调试路线
  static uint8_t debugNum = 4;        // 调试点的个数
  static uint8_t runTable[11] = {0};  // 选择的路线
  static int8_t runTableIndex = 0;    // 选择路线中的第一个调试点
  extern uint8_t runMethodNum;        // 路线的个数
  static uint8_t showFlag = 0;        // 0:刷新显示，1:不刷新显示
  if (flag == 0) {//选择路线，决定tableIndex的值
    if (key_Num == Key_ESC) {
      flag = 0;
      tableIndex = 0;
      debugNum = 4;
      showFlag = 0;
      runTableIndex = 0;
      memset(runTable, 0, sizeof(runTable));//恢复默认值
      return MY_OK;//确认退出
    } else if (key_Num == Key_OK) {//确认选择
      flag = 1;        // 进入 “选择调试点的个数”
      displayClean();  // 清屏，在这里顺便完成下一步的初始化
      displayStr("choose debugNum", Display_firstCol, Display_firstRow, RED);
    } else if (key_Num == Key_Down) {//选择路线减一
      tableIndex--;//选择路线减一
      showFlag = 0;//刷新显示
      if (tableIndex < 0) {
        tableIndex = runMethodNum - 1;//如果小于0，就回到最后一条路线
      }
    } else if (key_Num == Key_UP) {//选择路线加一
      tableIndex++;//选择路线加一
      showFlag = 0;//刷新显示
      if (tableIndex >= runMethodNum) {
        tableIndex = 0;//如果大于路线的个数，就回到第一条路线
      }
    }
    if (showFlag == 0) {//只有需要刷新显示时才刷新，减小时间开销
      displayClean();
      displayStr("choose table", Display_firstCol, Display_firstRow, RED);
      displayNum_len(tableIndex, Display_lastCol, Display_firstRow, 2);
      show_U8Array(Display_secondRow, runMethodTable[tableIndex],
                   strlen((const char *)runMethodTable[tableIndex]));//显示路线内容
      showFlag = 1;
    }
  } else if (flag == 1) {//选择调试点的个数，决定debugNum的值
    if (key_Num == Key_ESC) {//退出
      showFlag = 0;//选择路线的界面需要刷新
      debugNum = 4;//调试点的个数回到4
      flag = 0;//回到选择路线
    } else if (key_Num == Key_OK) {//确认选择
      showFlag = 0;//选择调试点的界面需要刷新
      flag = 2;//进入选择调试点
    } else if (key_Num == Key_Down) {//调试点的个数减一
      debugNum--;//调试点的个数减一
      if (debugNum < 3) {//如果小于3，就回到3
        debugNum = 3;
      }
    } else if (key_Num == Key_UP) {
      debugNum++;
      if (debugNum > 10 ||
          debugNum > strlen((const char *)runMethodTable[tableIndex])) {//如果大于10或者大于路线的长度，就回到10或者路线的长度
        debugNum = min(strlen((const char *)runMethodTable[tableIndex]), 10);
      }
    }
    displayNum(debugNum, Display_firstCol, Display_secondRow);//实时显示调试点的个数
  } else if (flag == 2) {//选择具体调试哪些点，决定runTableIndex的值
    if (showFlag == 0) {
      displayClean();
      displayStr("choose node", Display_firstCol, Display_firstRow, RED);
      displayNum_len(runTableIndex, Display_lastCol, Display_firstRow, 2);
      show_U8Array(Display_thirdRow, runMethodTable[tableIndex] + runTableIndex,
                   debugNum);//显示调试点，个数是上面选择的
      showFlag = 1;
    }
    if (key_Num == Key_ESC) {
      showFlag = 0;
      flag = 1;
      runTableIndex = 0;
      displayClean();  // 清屏，在这里顺便完成下一步的初始化
      displayStr("choose debugNum", Display_firstCol, Display_firstRow, RED);
    } else if (key_Num == Key_OK) {
      for (int i = 0; i < debugNum; i++) {
        runTable[i] = runMethodTable[tableIndex][i+runTableIndex];//装填进去，把选择的调试点复制到runTable中
      }
      runTable[debugNum] = 0;
      flag = 3;
    } else if (key_Num == Key_Down) {
      showFlag = 0;
      runTableIndex--;
      if (runTableIndex < 0) {//如果小于0，就变成最后一个调试点减去调试点的个数，即可以达到的最后的开始调试位置
        runTableIndex =
            strlen((const char *)runMethodTable[tableIndex]) - debugNum;
      }
    } else if (key_Num == Key_UP) {
      showFlag = 0;
      runTableIndex++;
      //如果大于路线的长度减去调试点的个数，就变成0，即可以达到的最开始的开始调试位置
      if (runTableIndex >
          strlen((const char *)runMethodTable[tableIndex]) - debugNum) {
        runTableIndex = 0;
      }
    }
  } else if (flag == 3) {//运行路线调试程序，只完成一小段路，所以不用重复初始化什么的
    static uint8_t gameRunFlag = 0;  // 0:未初始化，1：初始化
    if (gameRunFlag == 0) {//控制台只进行一次初始化
      gameRunFlag = 1;
      controlCenterInit(&gl_controlCenter, mapInfo, runTable);
    } else if (gameRunFlag == 1) {//控制台初始化完成，进入运行状态
      if (gl_controlCenter.update == MY_READY) {//如果路段完成，就更新路段
        LOG("INFO", "路段完成");
        controlCenterUpdate(&gl_controlCenter, mapInfo);
      } else if (gl_controlCenter.update == MY_EXIT) {//如果路线完成（全部完成了），就退出
        LOG("INFO", "路线完成");
        flag = 2;
        gameRunFlag = 0;
        showFlag = 0;
      }
      if (getGlobalTime() % 10 == 0) {
        findLine_Task(&gl_controlCenter);
        speedUpHandle_Task(&gl_controlCenter);
        roadBlocksHandle_Task(&gl_controlCenter);
        speedUpHandle_Task(&gl_controlCenter);
        seekNodeHandle_Task(&gl_controlCenter);
        carParkHandle_Task(&gl_controlCenter);
        rotateHandle_Task(&gl_controlCenter);
      }
    }
  }
  return MY_BUSY;
}
